package p.ithorns.framework.feign.enhance;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.StringUtils;

import javax.annotation.Nonnull;
import java.util.Map;
import java.util.Set;

/**
 * FeignServiceRegistrar
 *
 *
 * @author Ht.L
 * @date 2024-03-27 16:14
 * @since 1.0.0
 */
public class FeignSvcRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(@Nonnull BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
                                        @Nonnull BeanDefinitionRegistry registry) {

        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableFeignService.class.getName());
        assert annotationAttributes != null;

        ClassPathBeanDefinitionScanner scanner = new FeignSvcScanner(registry, beanFactory);
        scanner.addIncludeFilter(new AnnotationTypeFilter(FeignSvc.class));

        String[] basePackages = (String[]) annotationAttributes.get("basePackages");
        scanner.scan(basePackages);

//        try {
//            registerBeanDefinitions(scanner, basePackages);
//        } catch (ClassNotFoundException e) {
//            throw new RuntimeException(e);
//        }
    }

    private void registerBeanDefinitions(ClassPathBeanDefinitionScanner scanner, String[] basePackages)
            throws ClassNotFoundException {
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);
            for (BeanDefinition bd : candidates) {
                String beanClassName = bd.getBeanClassName();
                Class<?> interfaceClass = Class.forName(beanClassName);
                Object impl = beanFactory.getBean(interfaceClass);
                Object cglibProxy = createCglibProxy(impl, interfaceClass);
                String controller = StringUtils.capitalize(interfaceClass.getSimpleName()) + "$FeignController";
                ((DefaultListableBeanFactory)beanFactory).registerSingleton(controller, cglibProxy);
            }
        }
    }

    private <T> T createCglibProxy(Object target, Class<?> interfaceClass) {
        Enhancer enhancer = new Enhancer();

        Class<?>[] interfaces = {interfaceClass, FeignController.class};
        enhancer.setInterfaces(interfaces);

        // 设置方法拦截器
        enhancer.setCallback(new FeignSvcCglibProxy(target));
        // 创建代理类
        return (T) enhancer.create();
    }


}